/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <rom.prevot@gmail.com> wrote this file. As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return R. Prevot
 * ----------------------------------------------------------------------------
 */

/******************************************************************************\
 *          ____                _______    _____ _             _              *
 *         |  _ \              |__   __|  / ____| |           | |             *
 *         | |_) | ___  _ __ _ __ | | ___| (___ | |_ ___   ___| | __          *
 *         |  _ < / _ \| '__| '_ \| |/ _ \\___ \| __/ _ \ / __| |/ /          *
 *         | |_) | (_) | |  | | | | | (_) |___) | || (_) | (__|   <           *
 *         |____/ \___/|_|  |_| |_|_|\___/_____/ \__\___/ \___|_|\_\          *
 *                                                                            *
\******************************************************************************/

package app.tools.table;

import app.App;
import app.models.Categorie;
import app.models.Reference;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;

/*
 * To change this template, choose Tools | Templates and open the template in
 * the editor.
 */
/**
 *
 * @author Ghost
 */
public class SimpleTable2<T> extends JComponent {

    private List<T> elements = new ArrayList<T>();
    private List<Column<T, ?>> columns = new ArrayList<Column<T, ?>>();
    private JScrollPane scrollPane;
    private JTable table;
    private DefaultTableModel model;

    public SimpleTable2() {
        initComponents();
        render();
    }

    public SimpleTable2(List<T> els) {
        initComponents();

        for (T el : els) {
            addElement(el);
        }

        render();
    }

    /**
     * Add an element and render the table
     *
     * @param element the element tu append
     */
    public void addElement(T element) {
        elements.add(element);
        render();
    }

    /**
     * Add many elements and render the table
     *
     * @param elements
     */
    public void addElements(List<T> elements) {
        for (T el : elements) {
            addElement(el);
        }
    }

    /**
     * Replace elements by those passed and render the table
     *
     * @param elements
     */
    public void setElements(List<T> elements) {
        this.clear();
        addElements(elements);
    }

    /**
     * Remove un elements and render the table
     *
     * @param element
     */
    public void removeElement(T element) {
        elements.remove(element);
        render();
    }

    public void updateElement(T oldEl, T newEl) {
        int id = elements.indexOf(oldEl);
        if (id != -1) {
            elements.set(id, newEl);
            render();
        }
    }

    /**
     * Clear elements!
     */
    public void clear() {
        elements.clear();
        render();
    }

    /**
     * Add an header
     *
     * @param column
     */
    public void addColumn(Column<T, ?> column) {
        if (!columns.contains(column)) {
            columns.add(column);
        }
    }

    /**
     * Add multiples headers
     *
     * @param column
     */
    public void addColumns(Vector<Column<T, ?>> column) {
        for (Column c : column) {
            addColumn(c);
        }
    }

    /**
     * set headers (erase old)
     *
     * @param headers
     */
    public void setColumns(Vector<Column<T, ?>> column) {
        this.columns.clear();
        addColumns(column);
    }

    /**
     * Remove an header
     *
     * @param header
     */
    public void removeColumn(Column<T, ?> col) {
        columns.remove(col);
    }

    /**
     * Get the selected element or null if no selection
     *
     * @return
     */
    public T getSelectedElement() {
        if (table.getSelectedRowCount() == 0) {
            return null;
        }

        return elements.get(table.getSelectedRow());
    }

    /**
     * Force the selected element
     *
     * @param element
     */
    public void setSelectedElement(T element) {
        if (elements.contains(element)) {
            setSelectedRow(elements.indexOf(element));
        }
    }

    /**
     * Force the selected row
     *
     * @param row
     */
    public void setSelectedRow(int row) {
        table.getSelectionModel().setSelectionInterval(row, row);
    }

    public List<T> getElements() {
        return (elements != null) ? elements : new ArrayList<T>();
    }

    @Override
    public synchronized void addMouseListener(MouseListener l) {
        super.addMouseListener(l);
        table.addMouseListener(l);
    }

    @Override
    public synchronized void removeMouseListener(MouseListener l) {
        table.removeMouseListener(l);
        super.removeMouseListener(l);
    }

    public int rowAtPoint(Point point) {
        return table.rowAtPoint(point);
    }

    /**
     * Get headers and elements and computes them
     */
    public void render() {
        DefaultTableModel newModel = new DefaultTableModel() {

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        newModel.setRowCount(0);

        for (Column c : columns) {
            int iMax = elements.size();
            Object[] cData = new Object[elements.size()];
            for (int i = 0; i < iMax; i++) {
                T el = elements.get(i);
                cData[i] = c.getValue(el);
            }
            newModel.addColumn(c.getName(), cData);
        }

        table.setModel(newModel);
        model = newModel;
        repaint();
    }

    private void initComponents() {
        //inits        

        scrollPane = new JScrollPane();
        model = new DefaultTableModel(
                new Object[][]{
                    {null, null, null, null}
                },
                new String[]{
                    "Col1", "Col2", "Col3", "Col4"
                });
        table = new JTable(model) {

            @Override
            public Class<?> getColumnClass(int column) {
                Class<?> ret = super.getColumnClass(column);
                try {
                    Column c = columns.get(column);
                    ret = c.getResultClass();
                } catch (Exception e) {
                }
                return ret;
            }
        };

        //inserts
        scrollPane.setViewportView(table);
        table.setFillsViewportHeight(true);
        //Single selection
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.setCellSelectionEnabled(false);
        table.setRowSelectionAllowed(true);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        this.setLayout(new BorderLayout());
        this.add(scrollPane, BorderLayout.CENTER);
    }

    public static void main(String args[]) {
        List<Reference> references = new ArrayList<Reference>();
        final Random rnd = new Random();
        int max = (int) (rnd.nextDouble() * 30) + 3;

        final Categorie cat = new Categorie("Test");

        for (int i = 1; i < max; i++) {
            Reference ref = new Reference(
                    i,
                    "Designation produit " + i,
                    rnd.nextDouble() * 10,
                    rnd.nextDouble() * 9,
                    0,
                    rnd.nextInt() * 10,
                    true);
            ref.setCategorie(cat);
            references.add(ref);
        }

        final JFrame frame = new JFrame("Test SimpleTable");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final SimpleTable2<Reference> table = new SimpleTable2<Reference>(references);
        //Columns
        Column<Reference, String> categorieCol = new Column<Reference, String>() {

            @Override
            public String getValue(Reference element) {
                if (element != null) {
                    if (element.getCategorie() != null) {
                        return element.getCategorie().getLibelle();
                    } else {
                        return "no cat.";
                    }
                } else {
                    return "Rien";
                }
            }

            @Override
            public String getName() {
                return "Categorie";
            }
        };


        Column<Reference, String> designationCol = new Column<Reference, String>() {

            @Override
            public String getValue(Reference element) {
                if (element != null) {
                    return element.getDesignation();
                } else {
                    return "Rien";
                }
            }

            @Override
            public String getName() {
                return "Désignation";
            }
        };

        Column<Reference, ImageIcon> testCol = new Column<Reference, ImageIcon>() {

            @Override
            public ImageIcon getValue(Reference element) {
                Image img = App.createImage("resources/Ghost.png").getScaledInstance(26, 26, Image.SCALE_FAST);

                return new ImageIcon(img);
            }

            @Override
            public String getName() {
                return "test";
            }

            @Override
            public Class<?> getResultClass() {
                return ImageIcon.class;
            }
        };

        table.addColumn(designationCol);
        table.addColumn(categorieCol);
        table.addColumn(testCol);

        table.render();
        //final SimpleTable<Reference> table = new SimpleTable<Reference>();
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(table, BorderLayout.CENTER);
        frame.setSize(500, 300);
        frame.setLocationRelativeTo(null);

        JButton btn = new JButton("Magic!");
        btn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
            }
        });
        frame.add(btn, BorderLayout.SOUTH);
        frame.setVisible(true);
    }
}